/**
 * 
 */
package cm.iccsoft.android.telecomcost;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;

import cm.iccsoft.android.telecomcost.entities.Country;
import cm.iccsoft.android.telecomcost.entities.DailyThreshold;
import cm.iccsoft.android.telecomcost.entities.Month;
import cm.iccsoft.android.telecomcost.entities.MonthlyThreshold;
import cm.iccsoft.android.telecomcost.entities.Provider;
import cm.iccsoft.android.telecomcost.entities.Threshold;
import cm.iccsoft.android.telecomcost.entities.WeeklyThreshold;
import cm.iccsoft.android.telecomcost.entities.Zone;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.text.format.DateUtils;
import android.util.Log;

/**
 * @author Administrator
 * 
 */
public class DatabaseManager extends SQLiteOpenHelper {

	private final static String DB_NAME = "telecomcost.db";
	private final static int DB_VERSION = 19;

	/**
	 * @param context
	 * @param name
	 * @param factory
	 * @param version
	 */
	public DatabaseManager(Context context, String name, CursorFactory factory,
			int version) {
		super(context, DB_NAME, factory, DB_VERSION);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite
	 * .SQLiteDatabase)
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		Log.i("DatabaseManager", "Creating the databse...version : "
				+ DB_VERSION);

		String query = "CREATE TABLE json_data (type VARCHAR NOT NULL,json VARCHAR NOT NULL,id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL);";

		// create the json_data table.
		db.execSQL(query);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite
	 * .SQLiteDatabase, int, int)
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
		Log.i("DatabaseManager", "Upgrading the databse to the version : "
				+ DB_VERSION);
		db.delete("json_data", null, null);
	}

	public long saveData(String type, String json, long id) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put("type", type);
		values.put("json", json);
		long _id;

		if (id == -1) // new object
		{
			_id = db.insert("json_data", null, values);
		} else // that object already in db
		{
			_id = db.update("json_data", values, "id = " + id, null);
		}

		db.close();

		return _id;
	}

	public String getData(String type, long id) {
		String json = "";
		SQLiteDatabase db = this.getReadableDatabase();
		String query = "SELECT json,id FROM json_data WHERE type = "
				+ Utility.quote(type) + " AND id = " + Utility.quote(id);
		Cursor cur = db.rawQuery(query, null);

		if (cur.moveToNext()) {
			json = cur.getString(0);
		}

		cur.close();
		db.close();
		return json;
	}

	public long getNextId() {
		long id = 0;
		SQLiteDatabase db = this.getReadableDatabase();
		String query = "SELECT id FROM json_data ORDER BY id DESC";
		Cursor cur = db.rawQuery(query, null);

		if (cur.moveToNext()) {
			id = cur.getLong(0) + 1;
		}

		cur.close();
		db.close();
		return id;
	}

	public Map<String, String> getData(String type) {
		SQLiteDatabase db = this.getReadableDatabase();
		String query = "SELECT json,id FROM json_data WHERE type = "
				+ Utility.quote(type);
		Cursor cur = db.rawQuery(query, null);

		Map<String, String> strings = new HashMap<String, String>();

		int i = 0;
		while (cur.moveToNext()) {
			strings.put(cur.getString(1), cur.getString(0));
			i++;
		}

		cur.close();
		db.close();

		return strings;
	}

	public void deleteData(String type) {
		SQLiteDatabase db = this.getWritableDatabase();
		db.delete("json_data", "type = " + Utility.quote(type), null);
		db.close();
	}

	public boolean deleteData(String type, long id) {
		SQLiteDatabase db = this.getWritableDatabase();
		int rows = db.delete("json_data", "type = " + Utility.quote(type)
				+ " AND id = " + Utility.quote(id), null);
		db.close();
		return rows > 0;
	}

	public ArrayList<Zone> getZones() {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(Zone.PROP_TYPE);

		ArrayList<Zone> zones = new ArrayList<Zone>(map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			Zone zone = gson.fromJson(e.getValue(), Zone.class);
			zone.setId(Long.parseLong(e.getKey()));
			zones.add(zone);
		}

		return zones;
	}

	public ArrayList<DailyThreshold> getDailyThreshold(Month MonthOfYear,
			int weekOfMonth) {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(DailyThreshold.PROP_TYPE);

		ArrayList<DailyThreshold> thresholds = new ArrayList<DailyThreshold>(
				map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			DailyThreshold threshold = gson.fromJson(e.getValue(),
					DailyThreshold.class);
			if (threshold.getMonth() == MonthOfYear
					&& threshold.getWeekOfMonth() == weekOfMonth) {
				threshold.setId(Long.parseLong(e.getKey()));
				thresholds.add(threshold);
			}
		}

		ArrayList<DailyThreshold> return_thresholds = new ArrayList<DailyThreshold>();

		DailyThreshold mon_threshold = getDailyThreshold(Calendar.MONDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(mon_threshold);

		DailyThreshold tue_threshold = getDailyThreshold(Calendar.TUESDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(tue_threshold);

		DailyThreshold wed_threshold = getDailyThreshold(Calendar.WEDNESDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(wed_threshold);

		DailyThreshold thu_threshold = getDailyThreshold(Calendar.THURSDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(thu_threshold);

		DailyThreshold fri_threshold = getDailyThreshold(Calendar.FRIDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(fri_threshold);

		DailyThreshold sat_threshold = getDailyThreshold(Calendar.SATURDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(sat_threshold);

		DailyThreshold sun_threshold = getDailyThreshold(Calendar.SUNDAY,
				weekOfMonth, MonthOfYear, thresholds);
		return_thresholds.add(sun_threshold);

		return return_thresholds;
	}

	public ArrayList<Threshold> getThresholds() {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(Threshold.PROP_TYPE);

		ArrayList<Threshold> thresholds = new ArrayList<Threshold>(map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			Threshold threshold = gson.fromJson(e.getValue(), Threshold.class);
			threshold.setId(Long.parseLong(e.getKey()));
			thresholds.add(threshold);
		}

		return thresholds;
	}

	public DailyThreshold getDailyThreshold(int dayOfWeek, int weekOfMonth,
			Month month, ArrayList<DailyThreshold> thresholds) {
		Log.i("DatabaseManager",
				"loading DailyThreshold for "
						+ DateUtils.getDayOfWeekString(dayOfWeek,
								DateUtils.LENGTH_LONG));

		int index = 0;
		while (index < thresholds.size()) {
			DailyThreshold threshold = thresholds.get(index);
			if (threshold.getDayOfWeek() == dayOfWeek
					&& threshold.getWeekOfMonth() == weekOfMonth
					&& threshold.getMonth() == month) {
				return threshold;
			}
			index++;
		}

		return new DailyThreshold(0, dayOfWeek, weekOfMonth, month.getMonthOfYear());
	}

	public ArrayList<Country> getCountries() {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(Country.PROP_TYPE);

		ArrayList<Country> countries = new ArrayList<Country>(map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			Country country = gson.fromJson(e.getValue(), Country.class);
			country.setId(Long.parseLong(e.getKey()));
			countries.add(country);
		}

		return countries;
	}

	public Country getCountryByCode(String code) {
		ArrayList<Country> countries = getCountries();

		int index = 0;
		while (index < countries.size()) {
			if (countries.get(index).getCode().equals(code)) {
				return countries.get(index);
			}

			index++;
		}

		return null;
	}

	public ArrayList<Provider> getProviders() {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(Provider.PROP_TYPE);

		ArrayList<Provider> providers = new ArrayList<Provider>(map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			Provider provider = gson.fromJson(e.getValue(), Provider.class);
			provider.setId(Long.parseLong(e.getKey()));
			providers.add(provider);
		}

		return providers;
	}

	public void deleteZone(Zone zone) {
		Log.i("DatabaseManager", "deleting zone " + zone.getName() + "...");
		ArrayList<Country> countries = zone.getCountries();

		int index = 0;
		while (index < countries.size()) {
			deleCountry(countries.get(index));
			index++;
		}

		Log.i("DatabaseManager",
				deleteData(Zone.PROP_TYPE, zone.getId()) ? zone.getName()
						+ " deleted..." : "could not deleted zone "
						+ zone.getName());
	}

	public void deleCountry(Country country) {
		Log.i("DatabaseManager", "deleting country " + country.getName()
				+ "...");
		Gson gson = TelecomCost.getGson();
		Zone zone = gson.fromJson(getData(Zone.PROP_TYPE, country.getZoneId()),
				Zone.class);
		if (zone != null) {
			if (zone.remove(country)) {
				saveZone(zone, zone.getId());
			} else {
				Log.i("CountryListActivity", "could not remove the country "
						+ country.getName() + " from zone " + zone.getName());
			}
		} else {
			Log.i("CountryListActivity",
					"could not load the zone of the country "
							+ country.getName());
		}

		ArrayList<Provider> providers = country.getProviders();

		int index = 0;
		while (index < providers.size()) {
			Log.i("DatabaseManager", "deleting provider "
					+ providers.get(index).getName() + "...");
			deleteData(Provider.PROP_TYPE, providers.get(index).getId());
			index++;
		}

		deleteData(Country.PROP_TYPE, country.getId());
	}

	public boolean saveCountry(Country country, long id) {
		Log.i("DatabaseManager", "saving country " + country.getName());
		Gson gson = TelecomCost.getGson();
		Zone zone = gson.fromJson(getData(Zone.PROP_TYPE, country.getZoneId()),
				Zone.class);
		if (zone == null) {
			Log.i("DatabaseManager", "cannot save this country...zone is null");
			return false;
		}

		if (zone.getId() == -1) {
			Log.i("DatabaseManager",
					"cannot save this country...id of the zone not specified");
			return false;
		}

		if (country == null || country.getName() == null) {
			Log.i("DatabaseManager",
					"cannot save this country...country is null");
			return false;
		}
		if (country.getId() != -1) {
			if (zone.add(country)) {
				Log.i("DatabaseManager",
						"country added to zone " + zone.getName());
				saveZone(zone, zone.getId());
				Log.i("DatabaseManager",
						id == -1 ? "saving country " + country.getName()
								: "updating country " + country.getName());
				saveData(Country.PROP_TYPE, gson.toJson(country), id);
				return true;
			} else {
				Log.i("DatabaseManager", "could not add country to zone "
						+ zone.getName());
				return false;
			}
		}

		Log.i("DatabaseManager", "cannot save this country...set the id first");
		return false;
	}

	public boolean saveZone(Zone zone, long id) {
		if (zone == null) {
			Log.i("DatabaseManager", "cannot save this zone...zone is null");
			return false;
		}

		if (zone.getId() == -1) {
			Log.i("DatabaseManager", "cannot save this zone...set the id first");
			return false;
		}

		Log.i("DatabaseManager", id != -1 ? "updating zone " + zone.getName()
				: "saving zone " + zone.getName());
		Gson gson = TelecomCost.getGson();
		return saveData(Zone.PROP_TYPE, gson.toJson(zone), id) > 0;
	}

	public MonthlyThreshold saveDailyThreshold(DailyThreshold threshold,
			WeeklyThreshold weeklyThreshold, MonthlyThreshold monthTreshold)
			throws Exception {
		if (threshold == null) {
			Log.i("DatabaseManager",
					"cannot save this threshold...threshold is null");
			return null;
		}

		Gson gson = TelecomCost.getGson();
		// Log.i("DatabaseManager",
		// "we load the weekly threshold of this day");
		// WeeklyThreshold weeklyThreshold =
		// getWeeklyThreshold(threshold.getMonthOfYear(),threshold.getWeekOfMonth());

		double dayAmountInWeekThreshold = weeklyThreshold
				.getDayAmount(threshold.getDayOfWeek());

		Log.i("DatabaseManager",
				"we get the amount of the day " + threshold.getDayNameLong()
						+ " in week " + weeklyThreshold.getWeekOfMonth()
						+ "..." + dayAmountInWeekThreshold);

		double difference = 0;
		Log.i("DatabaseManager", "we update the threshold for the week ");
		if (dayAmountInWeekThreshold > threshold.getAmount()) {
			difference = dayAmountInWeekThreshold - threshold.getAmount();
			Log.i("DatabaseManager",
					"the dayAmountInWeekThreshold " + dayAmountInWeekThreshold
							+ " is greater than this daily threshold "
							+ threshold.getAmount() + "...we remove "
							+ difference + " from the weekly threshold");
			weeklyThreshold.setDayAmount(threshold.getDayOfWeek(),
					threshold.getAmount());
			weeklyThreshold.setAmount(weeklyThreshold.getAmount() - difference);
			saveData(WeeklyThreshold.PROP_TYPE, gson.toJson(weeklyThreshold),
					weeklyThreshold.getId());
		}

		if (dayAmountInWeekThreshold < threshold.getAmount()) {
			difference = threshold.getAmount() - dayAmountInWeekThreshold;
			Log.i("DatabaseManager",
					"the dayAmountInWeekThreshold " + dayAmountInWeekThreshold
							+ " is lower than this daily threshold "
							+ threshold.getAmount() + "...we add " + difference
							+ " to the weekly threshold");
			weeklyThreshold.setDayAmount(threshold.getDayOfWeek(),
					threshold.getAmount());
			weeklyThreshold.setAmount(weeklyThreshold.getAmount() + difference);
			saveData(WeeklyThreshold.PROP_TYPE, gson.toJson(weeklyThreshold),
					weeklyThreshold.getId());
		}

		// Log.i("DatabaseManager","we load the monthly threshold of this week");
		// MonthlyThreshold monthTreshold =
		// getMonthlyThreshold(threshold.getMonthOfYear());
		double weekAmountInMonthThreshold = monthTreshold
				.getWeekAmount(threshold.getWeekOfMonth());

		Log.i("DatabaseManager", "we update the threshold for the month ");
		if (weekAmountInMonthThreshold > weeklyThreshold.getAmount()) {
			Log.i("DatabaseManager", "the weekAmountInMonthThreshold "
					+ weekAmountInMonthThreshold
					+ " is greater than the weekly threshold amount "
					+ weeklyThreshold.getAmount());
			difference = weekAmountInMonthThreshold
					- weeklyThreshold.getAmount();

			Log.i("DatabaseManager", "we remove " + difference
					+ " from monthly threshold");
			monthTreshold.setAmount(monthTreshold.getAmount() - difference);
			monthTreshold.setWeekAmount(weeklyThreshold.getWeekOfMonth(),
					weeklyThreshold.getAmount());
			saveData(MonthlyThreshold.PROP_TYPE, gson.toJson(monthTreshold),
					monthTreshold.getId());
		}

		if (weekAmountInMonthThreshold < weeklyThreshold.getAmount()) {
			Log.i("DatabaseManager", "the weekAmountInMonthThreshold "
					+ weekAmountInMonthThreshold
					+ " is lower than the weekly threshold amount "
					+ weeklyThreshold.getAmount());
			difference = weeklyThreshold.getAmount()
					- weekAmountInMonthThreshold;

			Log.i("DatabaseManager", "we add " + difference
					+ " to monthly threshold");
			monthTreshold.setAmount(monthTreshold.getAmount() + difference);
			monthTreshold.setWeekAmount(weeklyThreshold.getWeekOfMonth(),
					weeklyThreshold.getAmount());
			saveData(MonthlyThreshold.PROP_TYPE, gson.toJson(monthTreshold),
					monthTreshold.getId());
		}

		String day = DateUtils.getDayOfWeekString(threshold.getDayOfWeek(),
				DateUtils.LENGTH_LONG);
		String month = threshold.getMonth().toString();

		Log.i("DatabaseManager",
				threshold.getId() != -1 ? "updating threshold for " + day
						+ " in week no " + threshold.getWeekOfMonth()
						+ " in month " + month : "saving threshold for " + day
						+ " in week no " + threshold.getWeekOfMonth()
						+ " in month " + month);

		saveData(DailyThreshold.PROP_TYPE, gson.toJson(threshold),
				threshold.getId());
		return monthTreshold;
	}

	public WeeklyThreshold getWeeklyThreshold(int monthOfYear, int weekOfMonth) {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(WeeklyThreshold.PROP_TYPE);

		for (Map.Entry<String, String> e : map.entrySet()) {
			WeeklyThreshold threshold = gson.fromJson(e.getValue(),
					WeeklyThreshold.class);
			if (threshold.getMonth().getMonthOfYear() == monthOfYear
					&& threshold.getWeekOfMonth() == weekOfMonth) {
				threshold.setId(Long.parseLong(e.getKey()));
				return threshold;
			}
		}

		return new WeeklyThreshold(0,weekOfMonth, new Month(monthOfYear));
	}

	public boolean saveProvider(Provider provider, Country country, long id) {
		if (provider == null) {
			Log.i("DatabaseManager",
					"cannot save this provider...provider is null");
			return false;
		}

		if (provider.getId() != -1) {
			if (country == null || country.getName() == null) {
				Log.i("DatabaseManager",
						"cannot save this provider...country is null");
				return false;
			}

			Gson gson = TelecomCost.getGson();

			if (country.add(provider)) {
				Log.i("DatabaseManager",
						"provider added to country " + country.getName());
				saveCountry(country, country.getId());
				Log.i("DatabaseManager",
						id == -1 ? "saving provider " + provider.getName()
								: "updating provider " + provider.getName());
				saveData(Provider.PROP_TYPE, gson.toJson(provider), id);
				return true;
			} else {
				Log.i("DatabaseManager",
						"could not add the provider " + provider.getName()
								+ " to country " + country.getName());
				return false;
			}
		}

		Log.i("DatabaseManager", "cannot save this provider...set the id first");
		return false;
	}

	public boolean saveCountry(Country country, Zone zone, long id) {
		Gson gson = TelecomCost.getGson();
		if (zone == null) {
			Log.i("DatabaseManager", "cannot save this country...zone is null");
			return false;
		}

		if (zone.getId() == -1) {
			Log.i("DatabaseManager",
					"cannot save this country...id of the zone not specified");
			return false;
		}

		if (country == null || country.getName() == null) {
			Log.i("DatabaseManager",
					"cannot save this country...country is null");
			return false;
		}
		if (country.getId() != -1) {
			if (zone.add(country)) {
				Log.i("DatabaseManager",
						"country added to zone " + zone.getName());
				saveZone(zone, zone.getId());
				Log.i("DatabaseManager",
						id == -1 ? "saving country " + country.getName()
								: "updating country " + country.getName());
				saveData(Country.PROP_TYPE, gson.toJson(country), id);
				return true;
			} else {
				Log.i("DatabaseManager", "could not add country to zone "
						+ zone.getName());
				return false;
			}
		}

		Log.i("DatabaseManager", "cannot save this country...set the id first");
		return false;
	}

	public ArrayList<MonthlyThreshold> getMonthlyThreshold() {
		ArrayList<MonthlyThreshold> thresholds = getMonthlyThresholds();

		ArrayList<MonthlyThreshold> return_thresholds = new ArrayList<MonthlyThreshold>();

		return_thresholds
				.add(getMonthlyThreshold(Calendar.JANUARY, thresholds));

		return_thresholds
				.add(getMonthlyThreshold(Calendar.FEBRUARY, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.MARCH, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.APRIL, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.MAY, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.JUNE, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.JULY, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.AUGUST, thresholds));

		return_thresholds.add(getMonthlyThreshold(Calendar.SEPTEMBER,
				thresholds));

		return_thresholds
				.add(getMonthlyThreshold(Calendar.OCTOBER, thresholds));

		return_thresholds
				.add(getMonthlyThreshold(Calendar.NOVEMBER, thresholds));

		return_thresholds
				.add(getMonthlyThreshold(Calendar.DECEMBER, thresholds));

		return return_thresholds;
	}

	public MonthlyThreshold getMonthlyThreshold(int monthOfYear,
			ArrayList<MonthlyThreshold> thresholds) {
		Log.i("DatabaseManager",
				"loading MonthlyThreshold for "
						+ DateUtils.getMonthString(monthOfYear,
								DateUtils.LENGTH_LONG));

		int index = 0;
		while (index < thresholds.size()) {
			MonthlyThreshold theshold = thresholds.get(index);
			if (theshold.getMonth().getMonthOfYear() == monthOfYear) {
				return theshold;
			}
			index++;
		}

		return new MonthlyThreshold(0,new Month(monthOfYear));
	}

	private ArrayList<MonthlyThreshold> getMonthlyThresholds() {
		Log.i("DatabaseManager", "getMonthlyThresholds...");
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(MonthlyThreshold.PROP_TYPE);

		ArrayList<MonthlyThreshold> thresholds = new ArrayList<MonthlyThreshold>(
				map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			MonthlyThreshold threshold = gson.fromJson(e.getValue(),
					MonthlyThreshold.class);
			threshold.setId(Long.parseLong(e.getKey()));
			thresholds.add(threshold);
		}

		return thresholds;
	}

	public MonthlyThreshold saveMonthlyThreshold(MonthlyThreshold threshold)
			throws Exception {
		if (threshold == null) {
			throw new Exception(
					"cannot save this threshold...threshold is null");
		}

		ArrayList<WeeklyThreshold> thresholds = getWeeklyThreshold(threshold
				.getMonth().getMonthOfYear());

		double totalAmount = getWeeklyThresholdTotalAmount(thresholds);

		double difference = 0;
		int index = 0;
		int amountToDispatch = 0;

		if (totalAmount > threshold.getAmount()) {
			Log.i("DatabaseManager",
					"the total amount of the weekly thresholds for this month "
							+ totalAmount
							+ " is greater than the monthly threshold amount "
							+ threshold.getAmount());
			difference = totalAmount - threshold.getAmount();
			amountToDispatch = (int) (difference / MonthlyThreshold.weeksOfMonth.length);

			while (index < MonthlyThreshold.weeksOfMonth.length) {
				WeeklyThreshold weeklyThreshold = getWeeklyThreshold(
						MonthlyThreshold.weeksOfMonth[index],
						threshold.getMonth().getMonthOfYear(),
						thresholds);
				Log.i("DatabaseManager",
						"we remove " + amountToDispatch
								+ " from weekly threshold for week "
								+ MonthlyThreshold.weeksOfMonth[index]);
				weeklyThreshold.setAmount(weeklyThreshold.getAmount()
						- amountToDispatch);
				threshold.setWeekAmount(weeklyThreshold.getWeekOfMonth(),
						weeklyThreshold.getAmount());
				saveWeeklyThreshold(weeklyThreshold, threshold);				
				index++;
			}
		}

		if (totalAmount < threshold.getAmount()) {
			Log.i("DatabaseManager",
					"the total amount of the weekly thresholds for this month "
							+ totalAmount
							+ " is lower than the monthly threshold amount "
							+ threshold.getAmount());
			difference = threshold.getAmount() - totalAmount;
//			amountToDispatch = (int) (difference / WeeklyThreshold.daysOfWeek.length);
//
//			while (index < WeeklyThreshold.daysOfWeek.length) {
//				DailyThreshold dailyThreshold = getDailyThreshold(
//						WeeklyThreshold.daysOfWeek[index],
//						threshold.getWeekOfMonth(), threshold.getMonthOfYear(),
//						thresholds);
//				Log.i("DatabaseManager",
//						"we add " + amountToDispatch
//								+ " to daily threshold for "
//								+ dailyThreshold.getDayNameLong());
//				dailyThreshold.setAmount(dailyThreshold.getAmount()
//						+ amountToDispatch);
//				saveData(DailyThreshold.PROP_TYPE, gson.toJson(dailyThreshold),
//						dailyThreshold.getId());
//				threshold.setDayAmount(dailyThreshold.getDayOfWeek(),
//						dailyThreshold.getAmount());
//				index++;
//			}
			
			amountToDispatch = (int) (difference / MonthlyThreshold.weeksOfMonth.length);

			while (index < MonthlyThreshold.weeksOfMonth.length) {
				WeeklyThreshold weeklyThreshold = getWeeklyThreshold(
						MonthlyThreshold.weeksOfMonth[index],
						threshold.getMonth().getMonthOfYear(),
						thresholds);
				Log.i("DatabaseManager",
						"we add " + amountToDispatch
								+ " to weekly threshold for week "
								+ MonthlyThreshold.weeksOfMonth[index]);
				weeklyThreshold.setAmount(weeklyThreshold.getAmount()
						+ amountToDispatch);
				threshold.setWeekAmount(weeklyThreshold.getWeekOfMonth(),
						weeklyThreshold.getAmount());
				saveWeeklyThreshold(weeklyThreshold, threshold);				
				index++;
			}
		}

		String month = DateUtils.getMonthString(threshold.getMonth().getMonthOfYear(),
				DateUtils.LENGTH_LONG);
		Log.i("DatabaseManager",
				threshold.getId() != -1 ? "updating threshold for " + month
						: "saving threshold for " + month);

		Gson gson = TelecomCost.getGson();
		saveData(MonthlyThreshold.PROP_TYPE, gson.toJson(threshold),
				threshold.getId());
		return threshold;
	}

	private double getWeeklyThresholdTotalAmount(
			ArrayList<WeeklyThreshold> thresholds) {
		Log.i("DatabaseManager",
				"we get the total amount of the weekly thresholds of this month...");
		double amount = 0;
		int index = 0;

		while (index < thresholds.size()) {
			amount = amount + thresholds.get(index).getAmount();
			index++;
		}

		Log.i("DatabaseManager", "total : " + amount);
		return amount;
	}

	public ArrayList<WeeklyThreshold> getWeeklyThreshold(int currentMonth) {
		ArrayList<WeeklyThreshold> thresholds = getWeeklyThresholds(currentMonth);

		ArrayList<WeeklyThreshold> return_thresholds = new ArrayList<WeeklyThreshold>();

		WeeklyThreshold week1_threshold = getWeeklyThreshold(
				MonthlyThreshold.PROP_WEEK1, currentMonth, thresholds);
		return_thresholds.add(week1_threshold);

		WeeklyThreshold week2_threshold = getWeeklyThreshold(
				MonthlyThreshold.PROP_WEEK2, currentMonth, thresholds);
		return_thresholds.add(week2_threshold);

		WeeklyThreshold week3_threshold = getWeeklyThreshold(
				MonthlyThreshold.PROP_WEEK3, currentMonth, thresholds);
		return_thresholds.add(week3_threshold);

		WeeklyThreshold week4_threshold = getWeeklyThreshold(
				MonthlyThreshold.PROP_WEEK4, currentMonth, thresholds);
		return_thresholds.add(week4_threshold);

		return return_thresholds;
	}

	private ArrayList<WeeklyThreshold> getWeeklyThresholds(int monthOfYear) {
		Gson gson = TelecomCost.getGson();
		Map<String, String> map = getData(WeeklyThreshold.PROP_TYPE);

		ArrayList<WeeklyThreshold> thresholds = new ArrayList<WeeklyThreshold>(
				map.size());

		for (Map.Entry<String, String> e : map.entrySet()) {
			WeeklyThreshold threshold = gson.fromJson(e.getValue(),
					WeeklyThreshold.class);
			if (threshold.getMonth().getMonthOfYear() == monthOfYear) {
				threshold.setId(Long.parseLong(e.getKey()));
				thresholds.add(threshold);
			}
		}

		return thresholds;
	}

	public WeeklyThreshold getWeeklyThreshold(int weekOfMonth, int monthOfYear,
			ArrayList<WeeklyThreshold> thresholds) {
		Log.i("DatabaseManager", "loading WeeklyThreshold for week "
				+ weekOfMonth);

		int index = 0;
		while (index < thresholds.size()) {
			WeeklyThreshold threshold = thresholds.get(index);
			if (threshold.getWeekOfMonth() == weekOfMonth) {
				return threshold;
			}
			index++;
		}

		return new WeeklyThreshold(0, weekOfMonth,new Month(monthOfYear));
	}

	public MonthlyThreshold saveWeeklyThreshold(WeeklyThreshold threshold,
			MonthlyThreshold monthTreshold) throws Exception {
		if (threshold == null) {
			Log.i("DatabaseManager",
					"cannot save this threshold...threshold is null");
			return null;
		}

		Gson gson = TelecomCost.getGson();
		Log.i("DatabaseManager",
				threshold.getId() != -1 ? "updating threshold for week "
						+ threshold.getWeekOfMonth()
						: "saving threshold for week "
								+ threshold.getWeekOfMonth());

		Log.i("DatabaseManager",
				"we load the daily thresholds for this week...");
		ArrayList<DailyThreshold> thresholds = getDailyThreshold(
				threshold.getMonth(), threshold.getWeekOfMonth());

		double totalAmount = getDailyThresholdTotalAmount(thresholds);

		double difference = 0;
		int index = 0;
		int amountToDispatch = 0;

		if (totalAmount > threshold.getAmount()) {
			Log.i("DatabaseManager",
					"the total amount of the daily thresholds for this week "
							+ totalAmount
							+ " is greater than the weekly threshold amount "
							+ threshold.getAmount());
			difference = totalAmount - threshold.getAmount();
			amountToDispatch = (int) (difference / WeeklyThreshold.daysOfWeek.length);

			while (index < WeeklyThreshold.daysOfWeek.length) {
				DailyThreshold dailyThreshold = getDailyThreshold(
						WeeklyThreshold.daysOfWeek[index],
						threshold.getWeekOfMonth(), threshold.getMonth(),
						thresholds);
				Log.i("DatabaseManager",
						"we remove " + amountToDispatch
								+ " from daily threshold for "
								+ dailyThreshold.getDayNameLong());
				dailyThreshold.setAmount(dailyThreshold.getAmount()
						- amountToDispatch);
				saveData(DailyThreshold.PROP_TYPE, gson.toJson(dailyThreshold),
						dailyThreshold.getId());
				threshold.setDayAmount(dailyThreshold.getDayOfWeek(),
						dailyThreshold.getAmount());
				index++;
			}
		}

		if (totalAmount < threshold.getAmount()) {
			Log.i("DatabaseManager",
					"the total amount of the daily thresholds for this week "
							+ totalAmount
							+ " is lower than the weekly threshold amount "
							+ threshold.getAmount());
			difference = threshold.getAmount() - totalAmount;
			amountToDispatch = (int) (difference / WeeklyThreshold.daysOfWeek.length);

			while (index < WeeklyThreshold.daysOfWeek.length) {
				DailyThreshold dailyThreshold = getDailyThreshold(
						WeeklyThreshold.daysOfWeek[index],
						threshold.getWeekOfMonth(), threshold.getMonth(),
						thresholds);
				Log.i("DatabaseManager",
						"we add " + amountToDispatch
								+ " to daily threshold for "
								+ dailyThreshold.getDayNameLong());
				dailyThreshold.setAmount(dailyThreshold.getAmount()
						+ amountToDispatch);
				saveData(DailyThreshold.PROP_TYPE, gson.toJson(dailyThreshold),
						dailyThreshold.getId());
				threshold.setDayAmount(dailyThreshold.getDayOfWeek(),
						dailyThreshold.getAmount());
				index++;
			}
		}

		Log.i("DatabaseManager", "we load the monthly threshold of this week");
		// MonthlyThreshold monthTreshold =
		// getMonthlyThreshold(threshold.getMonthOfYear());
		double weekAmountInMonthThreshold = monthTreshold
				.getWeekAmount(threshold.getWeekOfMonth());

		Log.i("DatabaseManager", "we update the threshold for the month ");
		if (weekAmountInMonthThreshold > threshold.getAmount()) {
			Log.i("DatabaseManager", "the weekAmountInMonthThreshold "
					+ weekAmountInMonthThreshold
					+ " is greater than the weekly threshold amount "
					+ threshold.getAmount());
			difference = weekAmountInMonthThreshold - threshold.getAmount();

			Log.i("DatabaseManager", "we remove " + difference
					+ " from monthly threshold");
			monthTreshold.setAmount(monthTreshold.getAmount() - difference);
			monthTreshold.setWeekAmount(threshold.getWeekOfMonth(),
					threshold.getAmount());
			saveData(MonthlyThreshold.PROP_TYPE, gson.toJson(monthTreshold),
					monthTreshold.getId());
		}

		if (weekAmountInMonthThreshold < threshold.getAmount()) {
			Log.i("DatabaseManager",
					"the weekAmountInMonthThreshold "
							+ weekAmountInMonthThreshold
							+ " is lower than the weekly threshold amount "
							+ threshold.getAmount());
			difference = threshold.getAmount() - weekAmountInMonthThreshold;

			Log.i("DatabaseManager", "we add " + difference
					+ " to monthly threshold");
			monthTreshold.setAmount(monthTreshold.getAmount() + difference);
			monthTreshold.setWeekAmount(threshold.getWeekOfMonth(),
					threshold.getAmount());
			saveData(MonthlyThreshold.PROP_TYPE, gson.toJson(monthTreshold),
					monthTreshold.getId());
		}

		saveData(WeeklyThreshold.PROP_TYPE, gson.toJson(threshold),
				threshold.getId());
		return monthTreshold;
	}

	private double getDailyThresholdTotalAmount(
			ArrayList<DailyThreshold> thresholds) {
		Log.i("DatabaseManager",
				"we get the total amount of the daily threshold of this week...");
		double amount = 0;
		int index = 0;

		while (index < thresholds.size()) {
			DailyThreshold threshold = thresholds.get(index);
			amount = amount + threshold.getAmount();
			index++;
		}

		Log.i("DatabaseManager", "total : " + amount);
		return amount;
	}
}
